package com.liuqi.loggers.core;

import com.liuqi.loggers.api.Logger;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 日志上下文实现类
 *
 * @author liuqi
 * @date 2024/10/14 15:53
 **/
public class LoggingContext implements Context {

    protected volatile boolean started = false;

    /**
     * 日志根实例输出器
     */
    final Logging root;

    private int size;

    private final String name;

    private Configuration configuration;

    /**
     * 日志缓存器
     */
    private final Map<String, Logger> loggerCache = new ConcurrentHashMap<String, Logger>();

    public LoggingContext(String name) {
        this(name, new Configuration());
    }

    public LoggingContext(String name, Configuration configuration) {
        if (name == null) throw new NullPointerException("LoggingContext name is null");
        if (configuration == null) throw new NullPointerException("LoggingContext configuration is null");

        this.name = name;
        this.configuration = configuration;

        this.root = new Logging(Context.ROOT_LOGGER_NAME, this);
        this.root.setLevel(configuration.getLevel());
        loggerCache.put(Context.ROOT_LOGGER_NAME, root);

        size = 1;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Logger getLogger(String name) {
        if (name == null) {
            throw new NullPointerException("name argument cannot be null");
        }

        // 如果 name 等于 ROOT 或者 root, 则返回 root日志实例
        if (Context.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
            return root;
        }

        // 如果缓存中存在
        Logger logger = loggerCache.get(name);
        if (logger != null) {
            return logger;
        }

        // 缓存中不存在日志实例, 创建日志实例

        synchronized (this) {
            Logging logging = new Logging(name, this);

            // 设置日志级别
            logging.setLevel(configuration.getLevel(name));

            // 添加到缓存列表
            loggerCache.put(name, logging);

            // 日志实例加 1
            incSize();

            return logging;
        }
    }

    private void incSize() {
        size++;
    }

    int size() {
        return size;
    }

    @Override
    public void append(LoggerEvent event) {
        for (Appender appender : configuration.getAppenderList()) {
            appender.append(event);
        }
    }

    @Override
    public void start() {
        for (LifeCycle lifeCycle : configuration.getAppenderList()) {
            lifeCycle.start();
        }
        started = true;
    }

    @Override
    public void stop() {
        for (LifeCycle lifeCycle : configuration.getAppenderList()) {
            lifeCycle.stop();
        }
        loggerCache.clear();
        configuration = null;
        started = false;
    }

    @Override
    public boolean isStarted() {
        return started;
    }

    public Configuration getConfiguration() {
        return configuration;
    }

    public void setConfiguration(Configuration configuration) {
        this.configuration = configuration;
    }

    public Map<String, Logger> getLoggerCache() {
        return loggerCache;
    }

}
